﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Documents;
using System.ComponentModel;
using System.Windows.Controls;
using System.Xml;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using SHomeWorkshop.LunarTools;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media.Imaging;

namespace SHomeWorkshop.LunarMind
{
    public class Comment : AdornerDecorator, INotifyPropertyChanged
    {
        public Comment(MainWindow editor, Title masterTitle)
        {
            this.editor = editor;
            this.masterTitle = masterTitle;
            this.masterTitleID = masterTitle.ID;

            this.connectLine.Stroke = this.borderColor;
            this.connectLine.StrokeThickness = 2.4;
            this.connectLine.StrokeDashArray = dashArray;

            //this.mainTextBlock.Foreground = Brushes.Brown;
            //this.mainTextBlock.Background = Brushes.Transparent;
            //this.mainTextBlock.ToolTip = "编辑文本：Ctrl+Enter（或双击）";
            //this.mainTextBlock.Cursor = Cursors.Hand;

            //this.mainTextBlock.MouseEnter += new MouseEventHandler(mainTextBlock_MouseEnter);
            //this.mainTextBlock.MouseLeave += new MouseEventHandler(mainTextBlock_MouseLeave);

            //this.mainTextBlock.MouseRightButtonUp += new MouseButtonEventHandler(mainTextBlock_MouseRightButtonUp);
            //this.mainTextBlock.MouseDown += new System.Windows.Input.MouseButtonEventHandler(mainTextBlock_MouseDown);
            //this.mainTextBlock.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(mainTextBlock_MouseLeftButtonDown);
            //this.Child = this.mainTextBlock;

            this.mainTextPanel.SizeChanged += new SizeChangedEventHandler(mainTextPanel_SizeChanged);
            this.Child = this.mainTextPanel;

            //AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainTextBlock);
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.mainTextPanel);

            //this.borderAdorner = new Adorners.CommentBorderAdorner(this.mainTextBlock, this);
            this.borderAdorner = new Adorners.CommentBorderAdorner(this.mainTextPanel, this);
            this.borderAdorner.MouseLeftButtonDown += new MouseButtonEventHandler(borderAdorner_MouseLeftButtonDown);

            //this.sizeHandlerAdorner = new Adorners.CommentSizeHandlerAdorner(this.mainTextBlock, this);
            this.sizeHandlerAdorner = new Adorners.CommentSizeHandlerAdorner(this.mainTextPanel, this);

            //this.summaryAdorner = new Adorners.CommentSummaryAdorner(this.mainTextBlock, this);
            this.summaryAdorner = new Adorners.CommentSummaryAdorner(this.mainTextPanel, this);

            adornerLayer.Add(this.borderAdorner);
            adornerLayer.Add(this.sizeHandlerAdorner);
            adornerLayer.Add(this.summaryAdorner);
        }

        void mainTextPanel_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            foreach (UIElement ue in this.mainTextPanel.Children)
            {
                TextBlock textBlock = ue as TextBlock;
                if (textBackground != null)
                {
                    textBlock.Width = textBlock.MaxWidth = (sender as StackPanel).ActualWidth;
                }
            }
        }

        /// <summary>
        /// 将原来的Attribute的Text文本转换成：
        /// TextSet节点中的Xml节点形式的文本。
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private static string ConvertToTextSetInnerXml(string source)
        {
            if (source == null || source.Length <= 0) return null;

            string result = source.Replace("\r\n", "</Text><Text>");
            return "<Text>" + result + "</Text>";
        }

        void borderAdorner_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //双击则编辑。
            if (e.ClickCount == 2)
            {
                SelectOnlySelf();
                Commands.EditCommentTextCommand.EditComment();
                e.Handled = true;
                return;
            }

            //准备拖动。
            editor.isDraggingComment = true;
            Point pt = e.GetPosition(this);
            editor.SetCommentDraggingSize(pt);
        }

        void textBlock_MouseLeave(object sender, MouseEventArgs e)
        {
            (sender as TextBlock).Foreground = textForeground;
            (sender as TextBlock).Background = textBackground;
        }

        void textBlock_MouseEnter(object sender, MouseEventArgs e)
        {
            if (textBackground == Brushes.Transparent)
            {
                (sender as TextBlock).Foreground = Brushes.White;
            }
            else
            {
                (sender as TextBlock).Foreground = textBackground;
            }

            if (textForeground == Brushes.Transparent)
            {
                (sender as TextBlock).Background = Brushes.Transparent;
            }
            else
            {
                (sender as TextBlock).Background = textForeground;
            }
        }

        void textBlock_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            s_ContextMenu.IsOpen = true;
            e.Handled = true;
        }

        static void cmiHideConnectLine_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedComment == null)
            {
                MessageBox.Show("请先选中一个“备注”！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedComment.MasterTitle == null ||
                Globals.MainWindow.SelectedComment.MasterTitle != Globals.MainWindow.RootTitle)
            {
                MessageBox.Show("　　只有中心标题（根标题）引出的备注才支持用户自定义连接线！" +
                    "其它标题引出的备注总是显示连接线的。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedComment.HideConnectLine == true) return;

            Comment curCmt = Globals.MainWindow.SelectedComment;

            ModifingItem mi = new ModifingItem() { ModifingName = "设置是否显示连接线" };

            Action actHideCommectLine = new Action(curCmt.ID, -1, curCmt.GetType().Name, "HideConnectLine",
                curCmt.HideConnectLine.ToString(), true.ToString());

            curCmt.HideConnectLine = true;

            mi.Add(actHideCommectLine);

            Globals.MainWindow.Do(mi);
            Globals.MainWindow.IsModified = true;
        }

        static void cmiShowConnectLine_Click(object sender, RoutedEventArgs e)
        {
            if (Globals.MainWindow.SelectedComment == null)
            {
                MessageBox.Show("请先选中一个“备注”！", Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedComment.MasterTitle == null ||
                Globals.MainWindow.SelectedComment.MasterTitle != Globals.MainWindow.RootTitle)
            {
                MessageBox.Show("　　只有中心标题（根标题）引出的备注才支持用户自定义连接线！" +
                    "非中心标题（根标题）引出的备注总是显示连接线的。", Globals.AppName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.MainWindow.SelectedComment.HideConnectLine == false) return;

            Comment curCmt = Globals.MainWindow.SelectedComment;

            ModifingItem mi = new ModifingItem() { ModifingName = "设置是否显示连接线" };

            Action actHideCommectLine = new Action(curCmt.ID, -1, curCmt.GetType().Name, "HideConnectLine",
                curCmt.HideConnectLine.ToString(), false.ToString());

            curCmt.HideConnectLine = false;

            mi.Add(actHideCommectLine);

            Globals.MainWindow.Do(mi);
            Globals.MainWindow.IsModified = true;
        }

        public static DoubleCollection dashArray = new DoubleCollection() { 1, 1 };

        void textBlock_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //双击则编辑。
            if (e.ClickCount == 2)
            {
                SelectOnlySelf();
                Commands.EditCommentTextCommand.EditComment();
                e.Handled = true;
                return;
            }

            //准备拖动。
            editor.isDraggingComment = true;
            Point pt = e.GetPosition(this);
            editor.SetCommentDraggingSize(pt);
        }

        void textBlock_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.SelectOnlySelf();
            e.Handled = true;
        }

        private Line connectLine = new Line();

        public System.Windows.Shapes.Line ConnectLine
        {
            get { return connectLine; }
        }

        private string id;

        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        private Brush textForeground = Brushes.Brown;

        public Brush TextForeground
        {
            get { return textForeground; }
            set
            {
                textForeground = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("TextForeground", ColorPicker.GetBrushName(value));
                }

                foreach (UIElement ue in this.mainTextPanel.Children)
                {
                    TextBlock tb = ue as TextBlock;
                    if (tb != null)
                    {
                        tb.Foreground = value;
                    }
                }
            }
        }

        private Brush textBackground = Brushes.Transparent;

        public Brush TextBackground
        {
            get { return textBackground; }
            set
            {
                textBackground = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("TextBackground", ColorPicker.GetBrushName(value));
                }
                this.mainTextPanel.Background = value;
            }
        }

        public void RebuildANewID()
        {
            id = Guid.NewGuid().ToString();
            if (this.xmlData != null)
            {
                this.xmlData.SetAttribute("ID", id);
            }
        }

        private LineDashType.DashType lineDash = LineDashType.DashType.Dot;

        public LineDashType.DashType LineDash
        {
            get { return lineDash; }
            set
            {
                lineDash = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("LineDash", lineDash.ToString());
                }

                RefreshDashType();
            }
        }

        private void RefreshDashType()
        {
            switch (lineDash)
            {
                case LineDashType.DashType.Dash:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dashCollection; break;
                    }
                case LineDashType.DashType.DashDotDot:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dashDotDotCollection; break;
                    }
                case LineDashType.DashType.Dot:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dotCollection; break;
                    }
                case LineDashType.DashType.Solid:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.solidCollection; break;
                    }
                default:
                    {
                        this.connectLine.StrokeDashArray = LineDashType.dashDotCollection; break;
                    }
            }
        }

        public void RefreshTbxCaret()
        {
            if (editor == null) return;

            if (editor.mainCanvas.Children.Contains(editor.tbxCaret) == false)
            {
                editor.mainCanvas.Children.Add(editor.tbxCaret);
                Canvas.SetZIndex(editor.tbxCaret, 0);
            }

            editor.tbxCaret.Width = this.MainTextPanel.Width;
            editor.tbxCaret.Height = this.MainTextPanel.Height;

            Canvas.SetLeft(editor.tbxCaret, Canvas.GetLeft(this));
            Canvas.SetTop(editor.tbxCaret, Canvas.GetTop(this));

            editor.tbxCaret.InvalidateArrange();
            editor.tbxCaret.UpdateLayout();

            editor.tbxCaret.Focus();
            editor.tbxCaret.Select(0, 0);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(object sender,
           PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(sender, e);
            }
        }

        /// <summary>
        /// 会重绘边框。
        /// </summary>
        public void RefreshLoaction()
        {
            if (MasterTitle == null)
            {
                this.Visibility = Visibility.Hidden;
                this.ConnectLine.Visibility = Visibility.Hidden;
                return;
            }
            else
            {
                if (MasterTitle.BeCollapsed)
                {
                    this.Visibility = Visibility.Hidden;
                    this.ConnectLine.Visibility = Visibility.Hidden;
                    return;
                }
                else
                {
                    this.Visibility = Visibility.Visible;

                    if (this.IsSummary)
                    {
                        double left;
                        if (MasterTitle.Editor.View == ViewMode.HorizontalList ||
                            MasterTitle.Editor.View == ViewMode.VerticalList ||         //横向列表视图和纵向列表视图概要均从右不从左。
                            MasterTitle.Direction == TitleDirection.Right)
                        {
                            left = MasterTitle.LeftTop.X + MasterTitle.NeedSize.Width - this.ActualWidth - 30;//30是左右边框宽度
                        }
                        else
                        {
                            left = MasterTitle.LeftTop.X - MasterTitle.NeedSize.Width + MasterTitle.ActualWidth + 30;
                        }


                        Canvas.SetLeft(this, left);

                        switch (Globals.MainWindow.View)
                        {
                            case ViewMode.HorizontalList:
                            case ViewMode.VerticalList:
                                {
                                    double top = Canvas.GetTop(MasterTitle) + (MasterTitle.NeedSize.Height - this.ActualHeight) / 2
                                        - MasterTitle.BaseTopAddValueFromSummary + 4;
                                    Canvas.SetTop(this, top);
                                    break;
                                }
                            default:
                                {
                                    double top = Canvas.GetTop(MasterTitle) + (MasterTitle.ActualHeight - this.ActualHeight) / 2 + 4;
                                    Canvas.SetTop(this, top);
                                    break;
                                }
                        }

                        this.connectLine.Visibility = Visibility.Hidden;//概要的连接线总是隐藏的。因为装饰器会绘制一个括弧来代替之。
                        return;
                    }

                    if (hideConnectLine)
                    {
                        this.ConnectLine.Visibility = Visibility.Hidden;
                    }
                    else
                    {
                        this.connectLine.Visibility = Visibility.Visible;
                    }
                }
            }

            if (this.masterTitle == editor.RootTitle)//从根标题引出的备注文本块固定位置。
            {
                Canvas.SetLeft(this, location.X);
                Canvas.SetTop(this, location.Y);
                RefreshConnectLine();
                return;
            }

            Rect masterRect = new Rect(MasterTitle.LeftTop.X, MasterTitle.LeftTop.Y,
                MasterTitle.ActualWidth, MasterTitle.ActualHeight);

            Point masterCenter = new Point(masterRect.Left + masterRect.Width / 2, masterRect.Top + masterRect.Height / 2);

            Point newLeftTop = new Point(masterCenter.X + location.X +
                (MasterTitle.Direction == TitleDirection.Right ? MasterTitle.IndentWidth : -MasterTitle.IndentWidth),
                masterCenter.Y + location.Y);

            Canvas.SetLeft(this, newLeftTop.X);
            Canvas.SetTop(this, newLeftTop.Y);

            this.borderAdorner.InvalidateVisual();

            this.InvalidateArrange();
            this.UpdateLayout();

            RefreshConnectLine();
        }

        private double rotateAngle = 0;

        public double RotateAngle
        {
            get { return rotateAngle; }
            set
            {
                if (value > 180)
                {
                    rotateAngle = 180;
                }
                else if (value < -180)
                {
                    rotateAngle = -180;
                }
                else
                {
                    rotateAngle = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("RotateAngle", rotateAngle.ToString());
                }

                RefreshRotateAngle();
            }
        }

        private static readonly Point defRenderCenter = new Point(0.5, 0.5);
        private static readonly RotateTransform defRotateTransform = new RotateTransform(0);

        private void RefreshRotateAngle()
        {
            if (this.RenderTransformOrigin != defRenderCenter)
            {
                this.RenderTransformOrigin = defRenderCenter;
            }

            if (rotateAngle == 0)
            {
                this.RenderTransform = defRotateTransform;
            }
            else
            {
                this.RenderTransform = new RotateTransform(rotateAngle);
            }
        }

        private bool hideConnectLine = false;

        /// <summary>
        /// 隐藏连接线。默认为false（显示）。
        /// </summary>
        public bool HideConnectLine
        {
            get { return hideConnectLine; }
            set
            {
                hideConnectLine = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("HideConnectLine", value.ToString());
                }
                RefreshConnectLine();
            }
        }

        public void RefreshConnectLine()
        {
            if (isSummary)
            {
                connectLine.Visibility = Visibility.Hidden;
                return;
            }

            if (this.masterTitle != null && this.masterTitle == editor.RootTitle)
            {
                if (this.hideConnectLine)
                {
                    if (connectLine.Visibility != Visibility.Hidden)
                    {
                        connectLine.Visibility = Visibility.Hidden;
                    }
                    return;
                }
                else
                {
                    if (connectLine.Visibility != Visibility.Visible)
                    {
                        connectLine.Visibility = Visibility.Visible;
                    }
                }
            }
            else
            {
                if (this.connectLine.Visibility != Visibility.Visible)//不是从根标题引出的备注总是显示连接线。
                {
                    this.connectLine.Visibility = Visibility.Visible;
                }
            }

            this.mainTextPanel.InvalidateArrange();
            this.mainTextPanel.UpdateLayout();

            if (MasterTitle == null || MasterTitle.ActualHeight <= 0 || MasterTitle.ActualWidth <= 0) return;

            Rect masterRect = new Rect(
                MasterTitle.LeftTop.X + MasterTitle.MainBorder.Margin.Left +
                (MasterTitle.Direction == TitleDirection.Right ? MasterTitle.IndentWidth : -MasterTitle.IndentWidth),
                MasterTitle.LeftTop.Y + MasterTitle.MainBorder.Margin.Top,
                MasterTitle.ActualWidth - MasterTitle.MainBorder.Margin.Left - MasterTitle.MainBorder.Margin.Right,
                MasterTitle.ActualHeight - MasterTitle.MainBorder.Margin.Top - MasterTitle.MainBorder.Margin.Bottom
                );

            Point masterCenter = new Point(masterRect.Left + masterRect.Width / 2, masterRect.Top + masterRect.Height / 2);
            Point newLeftTop = new Point(Canvas.GetLeft(this), Canvas.GetTop(this));

            Rect outBorderRect = new Rect(newLeftTop.X - 10, newLeftTop.Y - 10, this.ActualWidth + 20, this.ActualHeight + 20);

            if (outBorderRect.IntersectsWith(masterRect))
            {
                connectLine.Visibility = Visibility.Hidden;
            }
            else
            {
                PointToRect.ArrowPoints aptMasterTitle = PointToRect.GetCrossPointToRect(masterRect,
                    new Point(outBorderRect.Left + outBorderRect.Width / 2, outBorderRect.Top + outBorderRect.Height / 2));

                PointToRect.ArrowPoints aptComment = PointToRect.GetCrossPointToRect(outBorderRect, masterCenter);

                if (double.IsNaN(aptComment.Top.X) || double.IsNaN(aptComment.Top.Y) ||
                    double.IsNaN(aptMasterTitle.Top.X) || double.IsNaN(aptMasterTitle.Top.Y)) return;//防止首次读入时出问题。

                connectLine.X1 = aptComment.Top.X; connectLine.Y1 = aptComment.Top.Y;
                connectLine.X2 = aptMasterTitle.Top.X; connectLine.Y2 = aptMasterTitle.Top.Y;

                connectLine.Visibility = Visibility.Visible;
            }
        }

        private bool isSelected = false;

        public bool IsSelected
        {
            get { return isSelected; }
            set
            {
                isSelected = value;
                this.borderAdorner.InvalidateVisual();//选取框、装饰框由同一个装饰器实现。
                this.sizeHandlerAdorner.InvalidateVisual();
            }
        }

        public void SelectOnlySelf()
        {
            if (editor == null) return;

            if (editor.SelectedRelation != null) editor.SelectedRelation = null;
            if (editor.SelectedTitleImage != null) editor.SelectedTitleImage = null;
            if (editor.SelectedTitlesList.Count > 0) editor.ClearAllFromSelectedTitleList();

            editor.SelectedComment = this;
            this.IsSelected = true;
        }

        private Adorners.CommentBorderAdorner borderAdorner;

        private Adorners.CommentSizeHandlerAdorner sizeHandlerAdorner;

        //private TextBlock mainTextBlock = new TextBlock()
        //{
        //    Text = "..备注文本..",
        //    MinWidth = 20,
        //    MaxWidth = 400,
        //    TextWrapping = TextWrapping.Wrap,
        //};

        private StackPanel mainTextPanel = new StackPanel();

        public StackPanel MainTextPanel
        {
            get { return mainTextPanel; }
        }

        private double textBlockWidth = double.NaN;

        public double TextBlockWidth
        {
            get { return textBlockWidth; }
            set
            {
                if (double.IsNaN(value))
                {
                    textBlockWidth = value;
                }
                else if (value >= 20)
                {
                    textBlockWidth = value;
                }
                else
                {
                    textBlockWidth = 20;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("TextBlockWidth", textBlockWidth.ToString());
                }

                RefreshTextBlockWidth();
            }
        }

        private void RefreshTextBlockWidth()
        {
            if (double.IsNaN(textBlockWidth))
            {
                this.mainTextPanel.Width = double.NaN;
                this.mainTextPanel.MaxWidth = double.MaxValue;

                foreach (UIElement ue in this.mainTextPanel.Children)
                {
                    TextBlock textBlock = ue as TextBlock;
                    if (textBlock != null)
                    {
                        textBlock.TextWrapping = System.Windows.TextWrapping.NoWrap;
                        textBlock.MaxWidth = double.MaxValue;
                        textBlock.Width = double.NaN;
                    }
                }
            }
            else
            {
                this.mainTextPanel.Width = textBlockWidth;
                this.mainTextPanel.MaxWidth = textBlockWidth;

                foreach (UIElement ue in this.mainTextPanel.Children)
                {
                    TextBlock textBlock = ue as TextBlock;
                    if (textBlock != null)
                    {
                        textBlock.TextWrapping = System.Windows.TextWrapping.Wrap;
                        textBlock.MaxWidth = textBlockWidth;
                        textBlock.Width = textBlockWidth;
                    }
                }
            }

            RefreshConnectLine();
        }

        //public TextBlock MainTextBlock
        //{
        //    get { return mainTextBlock; }
        //}

        private XmlNode xmlData;

        public XmlNode XmlData
        {
            get { return xmlData; }
            set
            {
                xmlData = value;
                BuildComment();
            }
        }

        #region 已改为富文本，此属性已无必要存在。2011年9月5日
        //private string text;

        ///// <summary>
        ///// 显示的文本
        ///// </summary>
        //public string Text
        //{
        //    get { return text; }
        //    set
        //    {
        //        text = value;

        //        if (text == null || text.Length <= 0)
        //        {
        //            this.mainTextBlock.Text = "..备注文本..";
        //        }
        //        else
        //        {
        //            this.mainTextBlock.Text = value;
        //        }

        //        if (this.xmlData != null)
        //        {
        //            this.xmlData.SetAttribute("Text", value);
        //        }
        //    }
        //} 
        #endregion

        private static ContextMenu s_ContextMenu;

        public static ContextMenu S_ContextMenu
        {
            get { return Comment.s_ContextMenu; }
        }

        private static MenuItem cmiShowConnectLine;
        private static MenuItem cmiHideConnectLine;

        private static MenuItem cmiDot;
        private static MenuItem cmiDash;
        private static MenuItem cmiDashDot;
        private static MenuItem cmiDashDotDot;
        private static MenuItem cmiSolid;

        private static MenuItem cmiIsSummary;

        public static void ShowContextMenu()
        {
            if (s_ContextMenu != null) s_ContextMenu.IsOpen = true;
        }

        static Comment()
        {
            s_ContextMenu = new ContextMenu();
            s_ContextMenu.Opened += new RoutedEventHandler(contextMenu_Opened);

            cmiShowConnectLine = new MenuItem() { Header = "显示连接线(_S)", Height = 20 };
            cmiShowConnectLine.Click += new RoutedEventHandler(cmiShowConnectLine_Click);

            cmiHideConnectLine = new MenuItem() { Header = "隐藏连接线(_H)", Height = 20 };
            cmiHideConnectLine.Click += new RoutedEventHandler(cmiHideConnectLine_Click);

            s_ContextMenu.Items.Add(cmiShowConnectLine);
            s_ContextMenu.Items.Add(cmiHideConnectLine);

            s_ContextMenu.Items.Add(new Separator());

            cmiDot = new MenuItem() { Header = "点线(_T)", Height = 20 };
            cmiDash = new MenuItem() { Header = "划线(_A)", Height = 20 };
            cmiDashDot = new MenuItem() { Header = "点划线(_H)", Height = 20 };
            cmiDashDotDot = new MenuItem() { Header = "点点划线(_D)", Height = 20 };
            cmiSolid = new MenuItem() { Header = "实线(_O)", Height = 20 };

            cmiDot.Click += new RoutedEventHandler(cmiDot_Click);
            cmiDash.Click += new RoutedEventHandler(cmiDash_Click);
            cmiDashDot.Click += new RoutedEventHandler(cmiDashDot_Click);
            cmiDashDotDot.Click += new RoutedEventHandler(cmiDashDotDot_Click);
            cmiSolid.Click += new RoutedEventHandler(cmiSolid_Click);

            s_ContextMenu.Items.Add(cmiDot);
            s_ContextMenu.Items.Add(cmiDash);
            s_ContextMenu.Items.Add(cmiDashDot);
            s_ContextMenu.Items.Add(cmiDashDotDot);
            s_ContextMenu.Items.Add(cmiSolid);

            cmiIsSummary = new MenuItem() { Header = "显示为概要(_S)", Height = double.NaN };

            cmiIsSummary.Click += new RoutedEventHandler(cmiIsSummary_Click);

            s_ContextMenu.Items.Add(new Separator());

            s_ContextMenu.Items.Add(cmiIsSummary);
        }



        static void cmiIsSummary_Click(object sender, RoutedEventArgs e)
        {
            Comment cmt = Globals.MainWindow.SelectedComment;
            if (cmt == null || cmt.MasterTitle == null) return;

            Comment preSummary = cmt.MasterTitle.SummaryComment;

            if (cmt.IsSummary == false && preSummary != null)
            {
                MessageBox.Show("此备注文本块的宿主标题已具有一个概要型备注文本块。" +
                    "一个宿主标题最多只能设置一个备注文本块为概要。",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            ModifingItem mi = new ModifingItem() { ModifingName = "切换备注文本块概要状态" };

            bool newValue = !cmt.IsSummary;

            Action act = new Action(cmt.ID, -1, cmt.GetType().Name, "IsSummary",
                (!newValue).ToString(), newValue.ToString());

            cmt.IsSummary = newValue;

            mi.Add(act);

            cmt.editor.Do(mi);
            cmt.editor.RefreshTitleAndLinesLocation();
        }

        static void contextMenu_Opened(object sender, RoutedEventArgs e)
        {
            bool hideConnectLine;
            if (Globals.MainWindow.SelectedComment == null)
            {
                hideConnectLine = true;
            }
            else
            {
                hideConnectLine = Globals.MainWindow.SelectedComment.HideConnectLine;

                if (Globals.MainWindow.SelectedComment.MasterTitle != null &&
                    Globals.MainWindow.SelectedComment.MasterTitle.HigherLevelTitleID == null ||
                    Globals.MainWindow.SelectedComment.MasterTitle.HigherLevelTitleID.Length <= 0)
                {
                    cmiIsSummary.IsEnabled = false;
                }
                else
                {
                    cmiIsSummary.IsEnabled = true;
                }

                cmiIsSummary.IsChecked = Globals.MainWindow.SelectedComment.IsSummary;
            }

            cmiShowConnectLine.IsEnabled = hideConnectLine;
            cmiHideConnectLine.IsEnabled = !hideConnectLine;

            cmiDash.IsEnabled =
            cmiDashDot.IsEnabled =
            cmiDashDotDot.IsEnabled =
            cmiDot.IsEnabled =
            cmiSolid.IsEnabled = !hideConnectLine;

            if (!hideConnectLine)
            {
                Image imgLine = new Image();
                imgLine.Width = imgLine.Height = 16;
                imgLine.Source = new BitmapImage(new Uri("pack://Application:,,,/LunarMind;component/Resources/Icons/Selected.png"));

                switch (Globals.MainWindow.SelectedComment.LineDash)
                {
                    case LineDashType.DashType.Dash:
                        {
                            cmiDash.Icon = imgLine;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.DashDot:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = imgLine;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.DashDotDot:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = imgLine;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.Dot:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = imgLine;
                            cmiSolid.Icon = null;
                            break;
                        }
                    case LineDashType.DashType.Solid:
                        {
                            cmiDash.Icon = null;
                            cmiDashDot.Icon = null;
                            cmiDashDotDot.Icon = null;
                            cmiDot.Icon = null;
                            cmiSolid.Icon = imgLine;
                            break;
                        }
                }
            }
            else
            {
                cmiDash.Icon = null;
                cmiDashDot.Icon = null;
                cmiDashDotDot.Icon = null;
                cmiDot.Icon = null;
                cmiSolid.Icon = null;
            }
        }

        static void cmiSolid_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.Solid);
        }

        static void cmiDashDotDot_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.DashDotDot);
        }

        static void cmiDashDot_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.DashDot);
        }

        static void cmiDash_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.Dash);
        }

        static void cmiDot_Click(object sender, RoutedEventArgs e)
        {
            SetLineDash(LineDashType.DashType.Dot);
        }

        private static void SetLineDash(LineDashType.DashType newDashType)
        {
            if (Globals.MainWindow.SelectedComment != null)
            {
                Comment c = Globals.MainWindow.SelectedComment;
                if (c.LineDash != newDashType)
                {
                    ModifingItem mi = new ModifingItem() { ModifingName = "设置备注文本块连接线线型" };
                    Action actDashType = new Action(c.id, -1, c.GetType().Name, "LineDash",
                        c.LineDash.ToString(), newDashType.ToString());

                    c.LineDash = newDashType;

                    mi.Add(actDashType);
                    Globals.MainWindow.Do(mi);
                    Globals.MainWindow.IsModified = true;
                }
            }
        }

        public void BuildComment()
        {
            if (this.xmlData == null) return;

            XmlAttribute attrID = this.xmlData.GetAttribute("ID");
            if (attrID != null && attrID.Value.Length > 0)
            {
                this.id = attrID.Value;
            }
            else
            {
                RebuildANewID();
            }

            XmlNode textSetNode = this.xmlData.SelectSingleNode("TextSet");

            if (textSetNode == null)
            {
                textSetNode = this.xmlData.AppendXml("<TextSet/>");

                XmlAttribute attrText = this.xmlData.GetAttribute("Text");
                if (attrText != null)
                {
                    //this.text = attrText.Value;
                    //this.mainTextBlock.Text = this.text;

                    textSetNode.InnerXml = ConvertToTextSetInnerXml(attrText.Value);

                    this.xmlData.RemoveAttributeByName("Text");
                }
            }

            XmlAttribute attrTextBlockWidth = this.xmlData.GetAttribute("TextBlockWidth");
            if (attrTextBlockWidth != null)
            {
                double newWidth = double.Parse(attrTextBlockWidth.Value);

                if (newWidth >= 20 || double.IsNaN(newWidth))
                {
                    textBlockWidth = newWidth;
                }
                else
                {
                    textBlockWidth = 20;
                }

                this.RefreshTextBlockWidth();
            }

            XmlAttribute attrLocation = this.xmlData.GetAttribute("Location");
            if (attrLocation != null)
            {
                this.location = Point.Parse(attrLocation.Value);
            }

            XmlAttribute attrBorderColor = this.xmlData.GetAttribute("BorderColor");
            if (attrBorderColor != null)
            {
                this.borderColor = ColorPicker.GetBrushByName(attrBorderColor.Value);
                this.connectLine.Stroke = this.borderColor;
            }

            XmlAttribute attrTextBackground = this.xmlData.GetAttribute("TextBackground");
            if (attrTextBackground != null)
            {
                this.textBackground = ColorPicker.GetBrushByName(attrTextBackground.Value);
                this.MainTextPanel.Background = this.textBackground;
            }

            XmlAttribute attrTextForeground = this.xmlData.GetAttribute("TextForeground");
            if (attrTextForeground != null)
            {
                this.textForeground = ColorPicker.GetBrushByName(attrTextForeground.Value);
                //默认前景色到UpdateTextBlockFromXmlData()方法中设置了。2011年11月25日。
            }

            XmlAttribute attrHideConnectLine = this.xmlData.GetAttribute("HideConnectLine");
            if (attrHideConnectLine != null)
            {
                this.hideConnectLine = bool.Parse(attrHideConnectLine.Value);
            }

            XmlAttribute attrRotateAngle = this.xmlData.GetAttribute("RotateAngle");
            if (attrRotateAngle != null)
            {
                this.rotateAngle = double.Parse(attrRotateAngle.Value);
                RefreshRotateAngle();
            }

            XmlAttribute attrLineDash = this.xmlData.GetAttribute("LineDash");
            if (attrLineDash != null)
            {
                lineDash = (LineDashType.DashType)Enum.Parse(typeof(LineDashType.DashType), attrLineDash.Value);
                RefreshDashType();
            }

            XmlAttribute attrIsSummary = this.xmlData.GetAttribute("IsSummary");
            if (attrIsSummary != null)
            {
                isSummary = bool.Parse(attrIsSummary.Value);
                borderAdorner.InvalidateVisual();
            }

            UpdateTextBlockFromXmlData();

            RefreshLoaction();
        }

        /// <summary>
        /// 只应由UpdateTextBlockFromXmlData()方法内部使用。
        /// </summary>
        /// <returns></returns>
        private TextBlock NewTextBlock()
        {
            TextBlock textBlock = new TextBlock() { TextWrapping = TextWrapping.Wrap };

            //先设置为默认前景色。
            textBlock.Foreground = this.textForeground;

            textBlock.Background = Brushes.Transparent;
            textBlock.ToolTip = "编辑文本：Ctrl+Enter（或双击）";
            textBlock.Cursor = Cursors.SizeAll;
            textBlock.MouseEnter += new MouseEventHandler(textBlock_MouseEnter);
            textBlock.MouseLeave += new MouseEventHandler(textBlock_MouseLeave);
            textBlock.MouseRightButtonUp += new MouseButtonEventHandler(textBlock_MouseRightButtonUp);
            textBlock.MouseDown += new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseDown);
            textBlock.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(textBlock_MouseLeftButtonDown);

            return textBlock;
        }

        /// <summary>
        /// 根据XmlData中的TextSet中的文本内容来生成TextBlock的内容。
        /// </summary>
        public void UpdateTextBlockFromXmlData()
        {
            if (xmlData == null || this.mainTextPanel == null) return;

            this.mainTextPanel.Children.Clear();

            XmlNode textSetNode = xmlData.SelectSingleNode("TextSet");
            if (textSetNode == null) return;

            XmlNodeList nodes = textSetNode.SelectNodes("Text");
            if (nodes == null || nodes.Count <= 0)
            {
                return;
            }

            TextBlock textBlock = NewTextBlock();
            this.mainTextPanel.Children.Add(textBlock);

            foreach (XmlNode node in nodes)
            {
                if (node.InnerText == null || node.InnerText.Length == 0)
                {
                    //textBlock.Inlines.Add(new LineBreak());

                    textBlock = NewTextBlock();
                    this.mainTextPanel.Children.Add(textBlock);

                    continue;
                }

                Span span = new Span();
                Run run = new Run(Dialogs.TitleTextEditor.RestoreXmlChars(node.InnerXml));
                span.Inlines.Add(run);

                //取文本特性

                XmlAttribute attrTextAlignment = node.GetAttribute("TextAlignment");
                if (attrTextAlignment != null)
                {
                    textBlock.TextAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), attrTextAlignment.Value);
                }

                XmlAttribute attrForeground = node.GetAttribute("Foreground");
                if (attrForeground != null)
                {
                    Brush foreground = ColorPicker.GetBrushByName(attrForeground.Value);
                    if (foreground != null)
                    {
                        span.Foreground = foreground;
                        run.Tag = attrForeground.Value;//填空模式要用。
                    }
                }

                XmlAttribute attrBackground = node.GetAttribute("Background");
                if (attrBackground != null)
                {
                    Brush background = ColorPicker.GetBrushByName(attrBackground.Value);
                    if (background != null)
                        span.Background = background;
                }
                else
                {
                    span.Background = Brushes.Transparent;
                }

                XmlAttribute attrFontSize = node.GetAttribute("FontSize");
                if (attrFontSize != null)
                {
                    span.FontSize = double.Parse(attrFontSize.Value);
                }
                else
                {
                    span.FontSize = Globals.MainWindow.DefaultFontSize;
                }

                XmlAttribute attrFontWeight = node.GetAttribute("FontWeight");
                if (attrFontWeight != null && attrFontWeight.Value == "Bold")
                {
                    span.FontWeight = FontWeights.Bold;
                }

                XmlAttribute attrFontStyle = node.GetAttribute("FontStyle");
                if (attrFontStyle != null && attrFontStyle.Value == "Italic")
                {
                    span.FontStyle = FontStyles.Italic;
                }

                XmlAttribute attrUnderLine = node.GetAttribute("UnderLine");
                if (attrUnderLine != null && attrUnderLine.Value == "True")
                {
                    //span.TextDecorations.Add(TextDecorations.Underline);
                    span.TextDecorations.Add(Globals.UnderLineTextDecoration);
                    if (editor != null)
                    {
                        if (editor.ckxForceFillBlankView.IsChecked == true)
                        {
                            run.Foreground = Brushes.Transparent;
                        }
                    }
                    span.Tag = "FillBlank";
                }

                XmlAttribute attrStrikeLine = node.GetAttribute("StrikeLine");
                if (attrStrikeLine != null && attrStrikeLine.Value == "True")
                {
                    span.TextDecorations.Add(TextDecorations.Strikethrough);
                }

                XmlAttribute attrFontName = node.GetAttribute("FontName");
                if (attrFontName != null)
                {
                    FontFamily fontFamily = new FontFamily(attrFontName.Value);
                    if (fontFamily != null)
                        span.FontFamily = fontFamily;
                }

                XmlAttribute attrBaseLineAlignment = node.GetAttribute("BaseLineAlignment");
                if (attrBaseLineAlignment != null)
                {
                    switch (attrBaseLineAlignment.Value)
                    {
                        case "Top":
                            {
                                span.BaselineAlignment = BaselineAlignment.Top;

                                Binding fontSizeBinding = new Binding("ExFontSize");
                                fontSizeBinding.Source = this.Editor;
                                fontSizeBinding.Converter = MainWindow.halfTextSizeConverter;

                                span.SetBinding(Span.FontSizeProperty, fontSizeBinding);
                                break;
                            }
                        case "Bottom":
                            {
                                span.BaselineAlignment = BaselineAlignment.Bottom;

                                Binding fontSizeBinding = new Binding("ExFontSize");
                                fontSizeBinding.Source = this.Editor;
                                fontSizeBinding.Converter = MainWindow.halfTextSizeConverter;

                                span.SetBinding(Span.FontSizeProperty, fontSizeBinding);
                                break;
                            }
                        default:
                            {
                                span.BaselineAlignment = BaselineAlignment.Baseline;
                                break;
                            }
                    }
                }

                textBlock.Inlines.Add(span);
            }

            RefreshTextBlockWidth();

            if (this.IsSummary)
            {
                this.editor.RefreshTitleAndLinesLocation();
            }
        }

        private Brush borderColor = Brushes.Peru;

        public Brush BorderColor
        {
            get { return borderColor; }
            set
            {
                borderColor = value;
                connectLine.Stroke = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("BorderColor", ColorPicker.GetBrushName(value));
                }

                if (this.isSummary)
                {
                    this.summaryAdorner.InvalidateVisual();
                }
                else
                {
                    this.borderAdorner.InvalidateVisual();
                }
            }
        }

        private MainWindow editor;

        public MainWindow Editor
        {
            get { return editor; }
            set { editor = value; }
        }

        private string masterTitleID = null;

        /// <summary>
        /// 主标题的ID.
        /// </summary>
        public string MasterTitleID
        {
            get { return masterTitleID; }
            set
            {
                masterTitleID = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("MasterTitleID", value);
                }

                RefreshLoaction();
            }
        }

        private Title masterTitle;

        /// <summary>
        /// 主标题。
        /// </summary>
        public Title MasterTitle
        {
            get
            {
                if (masterTitle != null) return masterTitle;

                if (editor == null) return null;

                foreach (UIElement ue in editor.mainCanvas.Children)
                {
                    Title t = ue as Title;
                    if (t == null) continue;

                    if (t.ID == masterTitleID) return t;
                }

                return null;
            }
        }


        private Point location = new Point(-100, 100);//默认在主标题的左下角。

        /// <summary>
        /// 与主标题的相对位置。
        /// </summary>
        public Point Location
        {
            get { return location; }
            set
            {
                location = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("Location", value.ToString());
                }
                RefreshLoaction();
            }
        }

        /// <summary>
        /// 一次公式级的撤销操作。
        /// </summary>
        /// <param name="action">一次撤销或重做可以涉及到多个公式（因而包含多次公式级的撤销或重做）。</param>
        public virtual void Undo(Action action)
        {
            if (action != null)
            {
                SetProperty(action.PropertyOrActionTypeName, action.OldValue);
            }
        }

        /// <summary>
        /// 一次公式级的重做操作。
        /// </summary>
        /// <param name="action"></param>
        public virtual void Redo(Action action)
        {
            if (action != null)
            {
                SetProperty(action.PropertyOrActionTypeName, action.NewValue);
            }
        }

        public virtual void SetProperty(string propertyName, string value)
        {
            switch (propertyName)
            {
                // 已改为富文本实现，此属性已被取消。2011年9月5日
                //case "Text":
                //    {
                //        this.Text = value;
                //        break;
                //    }
                case "XmlDataInnerXml":
                    {
                        XmlNode textSetNode = this.xmlData.SelectSingleNode("TextSet");
                        if (textSetNode == null)
                        {
                            textSetNode = this.xmlData.AppendXml("<TextSet />");
                        }

                        if (textSetNode == null)
                        {
                            MessageBox.Show("发生意外，没有找到Comment的TextSet节点，且无法添加。编辑备注文本块失败。",
                                Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
                            return;
                        }

                        textSetNode.InnerXml = value;
                        UpdateTextBlockFromXmlData();
                        break;
                    }
                case "Location":
                    {
                        this.Location = Point.Parse(value);
                        RefreshLoaction();
                        break;
                    }
                case "BorderColor":
                    {
                        this.BorderColor = ColorPicker.GetBrushByName(value);
                        break;
                    }
                case "TextBackground":
                    {
                        this.TextBackground = ColorPicker.GetBrushByName(value); break;
                    }
                case "TextForeground":
                    {
                        this.TextForeground = ColorPicker.GetBrushByName(value); break;
                    }
                case "HideConnectLine":
                    {
                        this.HideConnectLine = bool.Parse(value); break;
                    }
                case "RotateAngle":
                    {
                        this.RotateAngle = double.Parse(value); break;
                    }
                case "LineDash":
                    {
                        this.LineDash = (LineDashType.DashType)Enum.Parse(typeof(LineDashType.DashType), value);
                        break;
                    }
                case "TextBlockWidth":
                    {
                        this.TextBlockWidth = double.Parse(value);
                        break;
                    }
                case "IsSummary":
                    {
                        this.IsSummary = bool.Parse(value);
                        break;
                    }
            }
        }

        private Adorners.CommentSummaryAdorner summaryAdorner;

        public Adorners.CommentSummaryAdorner SummaryAdorner
        {
            get { return summaryAdorner; }
        }

        private bool isSummary = false;

        /// <summary>
        /// 是否“概要”型备注文本块。
        /// 概要型备注文本块是自动布局的，用户不能移动其位置。
        /// 如果用户移动其位置，下次布局时，会自动回归原位！！！
        /// </summary>
        public bool IsSummary
        {
            get { return isSummary; }
            set
            {
                if (masterTitle == null) return;
                if (masterTitle.HigherLevelTitleID == null ||
                    masterTitle.HigherLevelTitleID.Length <= 0) return;//根标题引出的备注文本块不允许设置为“Summary”。

                isSummary = value;

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute("IsSummary", value.ToString());
                }

                RefreshSummary();
            }
        }

        private bool isFillBlankVisible = true;

        public bool IsFillBlankVisible
        {
            get { return isFillBlankVisible; }
            set
            {
                isFillBlankVisible = value;

                RefreshFillBlankVisible();
            }
        }

        private void RefreshFillBlankVisible()
        {
            if (editor == null) return;

            if (editor.tbtnFullScreen.IsChecked != true && editor.ckxForceFillBlankView.IsChecked != true)
            {
                foreach (TextBlock texbBlock in this.mainTextPanel.Children)
                {
                    foreach (var item in texbBlock.Inlines)
                    {
                        var span = item as Span;
                        if (span == null) continue;

                        if (span.Tag != null && span.Tag.ToString() == "FillBlank")
                        {
                            foreach (var item2 in span.Inlines)
                            {
                                var run = item2 as Run;
                                if (run == null) continue;

                                var oldBrush = ColorPicker.GetBrushByName(run.Tag as string);
                                run.Foreground = oldBrush == null ? span.Foreground : oldBrush;
                            }
                        }
                    }
                }
                return;//本来仅全屏状态下才有效果。2014年1月28日在主界面添加“强制呈现为填空模式”选择框。
            }

            //全屏状态下可以开关填空模式。
            foreach (TextBlock textBlock in this.mainTextPanel.Children)
            {
                foreach (var item in textBlock.Inlines)
                {
                    var span = item as Span;
                    if (span == null) continue;

                    if (span.Tag != null && span.Tag.ToString() == "FillBlank")
                    {
                        foreach (var item2 in span.Inlines)
                        {
                            var run = item2 as Run;
                            if (run == null) continue;

                            if (this.isFillBlankVisible)
                            {
                                //run.Foreground = ColorPicker.GetBrushByName(run.Tag as string);
                                run.Foreground = Brushes.Red;
                            }
                            else
                            {
                                run.Foreground = Brushes.Transparent;
                            }
                        }
                    }
                }
            }
        }

        internal void RefreshSummary()
        {
            if (editor != null)
            {
                editor.RefreshTitleAndLinesLocation();
            }

            this.borderAdorner.InvalidateVisual();
            this.summaryAdorner.InvalidateVisual();
            this.sizeHandlerAdorner.InvalidateVisual();
        }

    }
}
